<?php
/**
 * In this file the class '\BF\LocaleConfig' is defined.
 *
 * @author     Ulf Kadner <ulfikado@gmail.com>
 * @category   Beluga PHP5.3+ Framework
 * @copyright  (c) 2015, Ulfikado
 * @package    BF\Core
 * @since      2015-01-17 13:25
 * @version    0.1
 */

namespace BF
{

   /**
    * Defines all settings for creating a Locale instance.
    *
    * @since   v0.1
    */
   class LocaleConfig
   {

      # <editor-fold defaultstate="collapsed" desc=" - - -   C O N S T A N T S   - - - - - - - - - - - - - - - - - - - - - - - - - - -">

      /**
       * Used for {@see \BF\LocaleConfig::InitFromUrlPath}
       */
      const FIELD_TYPE_URL_PATH        = 1;

      /**
       * Used for {@see \BF\LocaleConfig::InitFromRequestData} $_GET
       */
      const FIELD_TYPE_REQUEST_GET     = 2;

      /**
       * Used for {@see \BF\LocaleConfig::InitFromRequestData} $_POST
       */
      const FIELD_TYPE_REQUEST_POST    = 3;

      /**
       * Used for {@see \BF\LocaleConfig::InitFromRequestData} $_SESSION
       */
      const FIELD_TYPE_REQUEST_SESSION = 4;

      /**
       * Used for {@see \BF\LocaleConfig::InitFromRequestData} $_COOKIE
       */
      const FIELD_TYPE_REQUEST_COOKIE  = 5;

      /**
       * Used for {@see \BF\LocaleConfig::InitFromRequestData} $_SERVER['HTTP_ACCEPT_LANGUAGE']
       */
      const FIELD_TYPE_ACCEPT_LANG     = 6;

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   F I E L D S   - - - - - - - - - - - - - - - - - - - - - - -">

      /**
       * Use current URL-Path from <code>$_SERVER['SCRIPT_URL']</code> to init locale from?
       *
       * If current URL-Path is defined in <code>$_SERVER['SCRIPT_URL']</code>, it will be checked, if it starts
       * with a valid LCID like <code style="color: blue">/de_AT/...</code> or <code style="color: blue">/de/...</code>.
       *
       * If so, the LCID will be used to init the Locale from.
       *
       * @var boolean
       */
      public $InitFromUrlPath = true;

      /**
       * Use current GET, POST, SESSION or COOKIE params to init locale from?
       *
       * The Name of the Parameter to use is defined by {@see \BF\Locale::$RequestDataParamName}.
       *
       * @var boolean
       */
      public $InitFromRequestData = true;

      /**
       * Use the here defined Name as GET, POST, SESSION or COOKIE parameter name, to init the locale from?
       *
       * The order is GET, POST, SESSION, COOKIE.
       *
       * If the value is defined by a array sub element, you can also define it by "foo['bar']" or "foo[0]" or
       * something else.
       *
       * @var string
       */
      public $RequestDataParamName = 'lang';

      /**
       * Use <code>$_SERVER['HTTP_ACCEPT_LANGUAGE']</code>, if defined, to init locale from?
       *
       * @var boolean
       */
      public $InitFromAcceptLanguage = true;

      /**
       * This locale is used by {@see \BF\Locale}, if no other usable locale was found. You have to define it before
       * you first access {@see \BF\Locale::GetInstance()}!
       *
       * @var string
       */
      public $FallbackLocaleString = 'en.utf-8';

      /**
       * This array defines the order, for getting the language to use. Use the \BF\LocaleConfig::FIELD_TYPE_*
       * constants.
       *
       * Default is:
       *
       * <pre>
       * array(
       *    \BF\LocaleConfig::FIELD_TYPE_REQUEST_GET,
       *    \BF\LocaleConfig::FIELD_TYPE_REQUEST_POST,
       *    \BF\LocaleConfig::FIELD_TYPE_REQUEST_SESSION,
       *    \BF\LocaleConfig::FIELD_TYPE_REQUEST_COOKIE,
       *    \BF\LocaleConfig::FIELD_TYPE_ACCEPT_LANG,
       *    \BF\LocaleConfig::FIELD_TYPE_URL_PATH
       * )
       * </pre>
       *
       * @var array
       */
      public $InitOrder = array(
         self::FIELD_TYPE_REQUEST_GET,
         self::FIELD_TYPE_REQUEST_POST,
         self::FIELD_TYPE_REQUEST_SESSION,
         self::FIELD_TYPE_REQUEST_COOKIE,
         self::FIELD_TYPE_ACCEPT_LANG,
         self::FIELD_TYPE_URL_PATH
      );

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - >   P U B L I C   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - -">

      /**
       * The constructor.
       *
       * @since  v0.1
       */
      public function __construct() { }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   M E T H O D S   - - - - - - - - - - - - - - - - - - - - - -">

      /**
       * Returns a array with all values of the current instance.
       *
       * The returned Array has the keys 'InitFromUrlPath', 'RequestDataParamName', 'InitFromRequestData',
       * 'InitFromAcceptLanguage' and 'FallbackLocaleString'.
       *
       * @return array
       */
      public function toArray()
      {

         return array(
            'InitFromUrlPath'        => $this->InitFromUrlPath,
            'RequestDataParamName'   => $this->RequestDataParamName,
            'InitFromRequestData'    => $this->InitFromRequestData,
            'InitFromAcceptLanguage' => $this->InitFromAcceptLanguage,
            'FallbackLocaleString'   => $this->FallbackLocaleString,
            'InitOrder'              => $this->InitOrder
         );

      }

      /**
       * Reinit's the instance data from the defined array, requires keys (caseless) are: 'InitFromUrlPath',
       * 'RequestDataParamName', 'InitFromRequestData', 'InitFromAcceptLanguage',
       * 'FallbackLocaleString' and 'InitOrder'
       *
       * @param  array   $array Getting the data of current instance from the array, defined here.
       * @return integer        Returns how many array values are used.
       */
      public function fromArray( array $array )
      {

         // Make lower case array keys
         $array = \array_change_key_case( $array );

         $handled = 0;

         if ( \array_key_exists( 'initfromurlpath', $array ) )
         {
            $this->InitFromUrlPath = \BF\FrameworkConfig::isBooleanTrue( $array[ 'initfromurlpath' ] );
            $handled++;
         }
         if ( \array_key_exists( 'requestdataparamname', $array ) )
         {
            $this->RequestDataParamName = \BF\FrameworkConfig::isBooleanTrue( $array[ 'requestdataparamname' ] );
            $handled++;
         }
         if ( \array_key_exists( 'initfromrequestdata', $array ) )
         {
            $this->InitFromRequestData = \BF\FrameworkConfig::isBooleanTrue( $array[ 'initfromrequestdata' ] );
            $handled++;
         }
         if ( \array_key_exists( 'initfromacceptlanguage', $array ) )
         {
            $this->InitFromAcceptLanguage = \BF\FrameworkConfig::isBooleanTrue( $array[ 'initfromacceptlanguage' ] );
            $handled++;
         }
         if ( \array_key_exists( 'fallbacklocalestring', $array ) )
         {
            $this->FallbackLocaleString = $array[ 'fallbacklocalestring' ];
            $handled++;
         }
         if ( \array_key_exists( 'initorder', $array ) && \is_array( $array[ 'initorder' ] ) )
         {
            $this->InitOrder = $array[ 'initorder' ];
            $handled++;
         }

         return $handled;

      }

      /**
       * Writes the current instance data to defined XML writer.
       *
       * The resulting XML looks like:
       *
       * <code>
       * &lt;LocaleConfig&gt;
       *    &lt;InitFrom urlpath="…" requestdata="…" acceptlanguage="…" /&gt;
       *    &lt;RequestDataParamName&gt;…&lt;/RequestDataParamName&gt;
       *    &lt;FallbackLocaleString&gt;…&lt;/FallbackLocaleString&gt;
       *    &lt;InitOrder&gt;…,…&lt;/InitOrder&gt;
       * &lt;/LocaleConfig&gt;
       * </code>
       *
       * @param \XMLWriter $w              The XML writer
       * @param string     $xmlElementName The name of the XML element that should contains the data
       */
      public function writeXml( \XMLWriter $w, $xmlElementName = 'LocaleConfig' )
      {

         // <LocaleConfig>
         $w->startElement( $xmlElementName );

         // <InitFrom
         $w->startElement( 'InitFrom' );
         // urlpath="…"
         $w->writeAttribute( 'urlpath',        $this->InitFromUrlPath         ? '1' : '0' );
         // requestdata="…"
         $w->writeAttribute( 'requestdata',    $this->InitFromRequestData     ? '1' : '0' );
         // acceptlanguage="…"
         $w->writeAttribute( 'acceptlanguage', $this->InitFromAcceptLanguage  ? '1' : '0' );
         // />
         $w->endElement();

         // <RequestDataParamName>…</RequestDataParamName>
         if ( ! empty( $this->RequestDataParamName ) )
         {
            $w->writeElement( 'RequestDataParamName', $this->RequestDataParamName );
         }

         // <FallbackLocaleString>…</FallbackLocaleString>
         if ( ! empty( $this->FallbackLocaleString ) )
         {
            $w->writeElement( 'FallbackLocaleString', $this->FallbackLocaleString );
         }

         // <InitOrder>…,…</InitOrder>
         if ( \is_array( $this->InitOrder ) && \count( $this->InitOrder ) > 0 )
         {
            $w->writeElement( 'InitOrder', \join( ',', $this->InitOrder ) );
         }

         // </LocaleConfig>
         $w->endElement();

      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   S T A T I C   M E T H O D S   - - - - - - - - - - - - - - -">

      /**
       * Extracts a \BF\LocaleConfig instance from a framework config XML element.
       *
       * @param  \SimpleXMLElement $fwConfigElement The XML root element of the whole BF framework config.
       * @param  string            $elementName     The name of the locale config XML element
       *                                            (defaults to 'LocaleConfig')
       * @return \BF\LocaleConfig  Return the new \BF\LocaleConfig instance, or boolean FALSE if no valid config
       *                           was found.
       */
      public static function FromXmlElement( \SimpleXMLElement $fwConfigElement, $elementName = 'LocaleConfig' )
      {
         if ( ! isset( $fwConfigElement->{$elementName} ) )
         {
            return false;
         }
         $element = $fwConfigElement->{$elementName};
         if ( ! isset( $element->InitFrom ) )
         {
            return false;
         }
         $config = new \BF\LocaleConfig();
         $config->InitFromUrlPath =
            \BF\XmlAttributeHelper::GetAttributeValue( $element->InitFrom, 'urlpath', '0' ) === '1';
         $config->InitFromRequestData =
            \BF\XmlAttributeHelper::GetAttributeValue( $element->InitFrom, 'requestdata', '1' ) === '1';
         $config->InitFromAcceptLanguage =
            \BF\XmlAttributeHelper::GetAttributeValue( $element->InitFrom, 'acceptlanguage', '1' ) === '1';
         if ( isset( $element->RequestDataParamName ) )
         {
            $config->RequestDataParamName =  (string) $element->RequestDataParamName;
         }
         if ( isset( $element->FallbackLocaleString ) )
         {
            $config->FallbackLocaleString =  (string) $element->FallbackLocaleString;
         }
         if ( isset( $element->InitOrder ) )
         {
            $initOrder = \explode( ',', (string) $element->InitOrder );
            $isUsable  = true;
            for ( $i = 0; $i < \count( $initOrder ); ++$i )
            {
               if ( ! \is_numeric( $initOrder[ $i ] ) )
               {
                  $isUsable = false;
                  break;
               }
               $initOrder[ $i ] = intval( $initOrder[ $i ] );
               if ( $initOrder[ $i ] < 1 || $initOrder[ $i ] > 6 )
               {
                  $isUsable = false;
                  break;
               }
            }
            $initOrder2 = \array_unique( $initOrder );
            if ( $isUsable && \count( $initOrder2 ) > 0 )
            {
               $config->InitOrder = $initOrder2;
            }
         }
         return $config;
      }

      # </editor-fold>

   }

}

